package com.meme.io.editor;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.meme.editor.EntityObject;
import com.meme.editor.PropertyValueModification;
import com.meme.editor.PropertyValueModificationList;
import com.meme.editor.PropertyValueModification;
import com.meme.editor.level.*;
import com.meme.editor.level.define.DefineFile;
import com.meme.editor.level.define.ActorTemplate;
import com.meme.util.XmlUtil;
import com.meme.util.FileUtil;

import com.meme.editor.property.Property;

public class LevelXmlFileLoader {
	
	static Logger logger = Logger.getLogger(LevelXmlFileLoader.class);
	
	
	String mLevelFilename;
	DefineFile mDefineFile;

	public LevelFile loadFromXmlDocument(Document document, String filename) 
	{
		mLevelFilename = filename;
		
		LevelFile levelFile = new LevelFile();


		levelFile.setHostFilename(filename);
		
		loadLevelFile(document, levelFile);
		evalEntityRefs(levelFile);

		//levelFile._testFunc();

		return levelFile;
	}

	
//================================================================================
// 
//================================================================================

	void loadLevelFile (Document document, LevelFile levelFile)
	{
		Element levelElement = XmlUtil.getChildElementByName (document, "Level");
		
		String version = levelElement.getAttribute("version");		
		logger.assertLog(version.equals("1.0"), "version is not 1.0.");
		
		{
			// special handling
			Element propertiesElement = XmlUtil.getChildElementByName (levelElement, "Properties");
			Element[] groupElements = XmlUtil.getChildElementsByName (propertiesElement, "PropertyGroup");
			for (Element groupElement : groupElements)
			{
				if (groupElement.getAttribute("name").equals (LevelFile.GroupName_LevelGroup) )
				{
					Element[] propertyElements = XmlUtil.getChildElementsByName (groupElement, "Property");
					for (Element propertyElement : propertyElements)
					{
						if (propertyElement.getAttribute("name").equals (LevelFile.PropertyName_DefineFile) )
						{
							String oldValue = propertyElement.getAttribute("value");
							if (oldValue.length() > 0)
							{
								propertyElement.setAttribute("value", FileUtil.getFullPathFilename(oldValue, mLevelFilename));
							}
						}
					}
				}
			}

			// level properties
			levelFile.setUserObject (retrievePropertyValueModificationListFrom (levelElement));		
			applyPropertyValueModifications (levelFile, false);
			levelFile.setUserObject (null);
		}
		
		mDefineFile = levelFile.getDefineFile();
		if (mDefineFile == null)
			return;
		
		// load actors
		{
			Element actorsElement = XmlUtil.getChildElementByName (levelElement, "Actors");			
			Element[] actorElements = XmlUtil.getChildElementsByName (actorsElement, "Actor");
			for (Element actorElement : actorElements)
			{
				String templateName = actorElement.getAttribute ("template");
				ActorTemplate actorTemplate = mDefineFile.getActorTemplate (templateName);
				
				String actorName = actorElement.getAttribute ("name");
				
				Actor actor = levelFile.createActorFromTemplate(actorTemplate);
				//actor.setName(actorName);
				
				PropertyValueModificationList actorPropertyModList = retrievePropertyValueModificationListFrom (actorElement); 
				PropertyValueModification actorNameMod = null;
				for (PropertyValueModification mod : actorPropertyModList)
				{
					if (mod.mGroupName.equals(EntityObject.GroupName_Entity)
						&& mod.mPropertyName.equals(EntityObject.PropertyName_Name)	)
					{
						actorNameMod = mod;
						break;
					}
				}
				actor.setName((String)actorNameMod.mNewValue);
				actorPropertyModList.remove(actorNameMod);
				actor.setUserObject (actorPropertyModList);
				
				
				//
				Element appearancesElement = XmlUtil.getChildElementByName (actorElement, "Appearances");				
				Element[] appearanceElements = XmlUtil.getChildElementsByName (appearancesElement, "Appearance");
				for (Element appearanceElement : appearanceElements)
				{
					Appearance appearance = null;
					
					PropertyValueModificationList modList = retrievePropertyValueModificationListFrom (appearanceElement);
					for (PropertyValueModification mod : modList)
					{
						if (mod.mGroupName.equals(EntityObject.GroupName_Entity) && mod.mPropertyName.equals(EntityObject.PropertyName_Name))
						{
							String appearanceName = (String) mod.mNewValue;
							appearance = (Appearance) actor.getChildByName(appearanceName);
							break;
						}
					}
					
					if (appearance != null)				
						appearance.setUserObject (retrievePropertyValueModificationListFrom (appearanceElement));
				}
			}						
		}
		
		// load movie animations
		{
			
		}
	}
	
//================================================================================
// 
//================================================================================
		
	PropertyValueModificationList retrievePropertyValueModificationListFrom (Element entityElement)
	{
		PropertyValueModificationList mods = new PropertyValueModificationList();
		
		Element propertiesElement = XmlUtil.getChildElementByName(entityElement, "Properties");	
		
		Element[] propertyGroupElements = XmlUtil.getChildElementsByName (propertiesElement, "PropertyGroup");
		for (Element propertyGroupElement : propertyGroupElements)
		{
			String groupName = propertyGroupElement.getAttribute("name");
			Element[] propertyElements = XmlUtil.getChildElementsByName (propertyGroupElement, "Property");
			for (Element propertyElement : propertyElements)
			{
				String propertyName = propertyElement.getAttribute("name");
				String propertyValue = propertyElement.getAttribute("value");
				mods.add (new PropertyValueModification (groupName, propertyName, propertyValue));
			}
		}
		
		return mods;
	}
	

	
//================================================================================
// eval EntityRefs
//================================================================================
	
	void evalEntityRefs (LevelFile levelFile) 
	{
		EntityObject.sDisableValueValidating = true;
		
			applyPropertyValueModifications (levelFile, true);

		EntityObject.sDisableValueValidating = false;
	}
	
	void applyPropertyValueModifications (EntityObject entity, boolean recursive)
	{
		PropertyValueModificationList modList = (PropertyValueModificationList) entity.getUserObject();
		if (modList != null)
		{
			for (PropertyValueModification mod : modList)
			{
				Property property = entity.getPublicProperty (mod.mGroupName, mod.mPropertyName);
				
				if (property != null)
				{
					property.modifyValue (mod.mNewValue);
					mod.mNewValue = property.getValue();
				}
				else
					logger.warn ("No such property: group=" + mod.mGroupName + ", name=" + mod.mPropertyName);
			}
			
			entity.modifyPropertyValues (modList);
		}
		entity.setUserObject (null);
		
		if ( recursive )
		{
			for (EntityObject child : entity.getChildren())
			{
				applyPropertyValueModifications (child, true);
			}
		}
	}
}
